#include "Vampire.h"
#include "Player.h"
#include "DestroyGameObjectMessage.h"
#include "../SGD Wrappers/SGD_GraphicsManager.h"
#include "GameplayState.h"
#include "Game.h"
#include "Boss.h"
#include "CreatePortalMessage.h"
#include "TileSystem.h"
#include "CreateBulletMessage.h"
#include "CreateBatMessage.h"
#include "Projectile.h"
#include "../SGD Wrappers/SGD_AudioManager.h"

Vampire::Vampire()
{
	playerPos = gameplay->GetPlayer()->GetPosition();

	StartAnimation("vampireidle");
	RegisterForEvent("TRANSFORM_COMPLETE");

	transforms[0] = false;
	transforms[1] = false;
	transforms[2] = false;
	
	SetLevel(GameplayState::GetInstance()->GetCurrLevel());
}

void Vampire::Update(float elapsedTime)
{
	dt = elapsedTime;

	SetFacing(gameplay->GetPlayer()->GetPosition().x < GetPosition().x ? -1 : 1);

	if (currAttackStrat == VAMPIRE_ATTACK)
		shotCooldown -= elapsedTime;

	playerPos = gameplay->GetPlayer()->GetPosition();
	// will call attack, etc
	Enemy::Update(elapsedTime);

	// failed checks in Enemy::Update
	if (!updating) return;

	// distance from player
	distanceToPlayer = (playerPos - m_ptPosition).ComputeLength();
	aiming.x = playerPos.x < m_ptPosition.x ? -1.0f : 1.0f;
}

void Vampire::Render()
{
	if (currAttackStrat == BAT_ATTACK) return;
	
	if (SGD::InputManager::GetInstance()->IsKeyDown(SGD::Key::F4))
		m_iHealth = 0;

	Boss::Render();
	AnimationSystem::GetInstance()->Render({ GetPosition().x - Game::GetInstance()->GetCameraPos().x, GetPosition().y - Game::GetInstance()->GetCameraPos().y }, animInfo);
}

/*virtual*/ bool Vampire::DoAttack()
{
	// attack if within 600
	return ((GameplayState::GetInstance()->GetPlayer()->GetPosition() - m_ptPosition).ComputeLength() < 600.0f);
}

/*virtual*/ void Vampire::Attack()
{
	//Decide when to switch to bat
	float healthRatio = (float)m_iHealth / m_iMaxHealth;
	if (!transforms[0] && healthRatio > 0.75f && healthRatio < 0.875f)
	{
		//Time to become a bat
		currAttackStrat = VAMPIRE_TRANSFORMING;
		tempHealth = m_iHealth;

		StartAnimation("vampiretransform");
		transforms[0] = true;
	}
	else if (!transforms[1] && healthRatio > 0.5f && healthRatio < 0.65f)
	{
		currAttackStrat = VAMPIRE_TRANSFORMING;
		tempHealth = m_iHealth;

		StartAnimation("vampiretransform");
		transforms[1] = true;
	}
	else if (!transforms[2] && healthRatio > 0.25f && healthRatio < 0.375f)
	{
		currAttackStrat = VAMPIRE_TRANSFORMING;
		tempHealth = m_iHealth;

		StartAnimation("vampiretransform");
		transforms[2] = true;
	}

	switch (currAttackStrat)
	{
	default:
		break;
	case Vampire::BAT_ATTACK:
		// vampire object isn't deleted, still collides. This will move him away from the player (see functions)
		MoveTowardsPlayer();
		break;
	case Vampire::VAMPIRE_ATTACK:
		VampireAttack();
		break;
	case Vampire::VAMPIRE_TRANSFORMING:
		break;
	case Vampire::VAMPIRE_BITE:
		VampireAttack();
		break;
	}
}

void Vampire::VampireAttack()
{
	//if close enough stop advancing
	if (distanceToPlayer < 10 && currAttackStrat != VAMPIRE_BITE)
	{
		// switch to melee state (vampire_bite)
		currAttackStrat = VAMPIRE_BITE;
		m_vtVelocity.x = 0.0f;

		StartAnimation("vampirebiting");
		return;
	}

	// retreat
	else if (distanceToPlayer < 10 && currAttackStrat == VAMPIRE_BITE)
		Retreat();

	if (distanceToPlayer > 100 && retreating)
	{
		retreating = false;
		currAttackStrat = VAMPIRE_ATTACK;
	}

	// Attack range: within  50 - 300 of player
	if (distanceToPlayer > 100 && distanceToPlayer < 300 && currAttackStrat == VAMPIRE_ATTACK)
	{
		// charge the player when above 75% health
		if (GetHealth() > GetMaxHealth() * .75f)
		{
			MoveTowardsPlayer();
			if (currAttackStrat != VAMPIRE_TRANSFORMING && currAttackStrat != BAT_ATTACK)
			{
				// constantly attacking (spit at player)
				if (shotCooldown < 0.0f)
				{
					if (bloodRage)
						shotCooldown = .50f;
					else
						shotCooldown = 2.5f;

					CreateBulletMessage * Msg = new CreateBulletMessage{ this, RotationToPlayer(), false };
					Msg->QueueMessage();
				}
			}

			retreating = false;
		}
		// retreat when between 50% and 75% health
		else if (GetHealth() > GetMaxHealth() * .50f && GetHealth() < GetMaxHealth() * .75f)
		{
			Retreat();
			if (currAttackStrat != VAMPIRE_TRANSFORMING && currAttackStrat != BAT_ATTACK)
			{
				// constantly attacking
				if (shotCooldown < 0.0f)
				{
					if (bloodRage)
						shotCooldown = .50f;
					else
						shotCooldown = 2.5f;

					CreateBulletMessage * Msg = new CreateBulletMessage{ this, RotationToPlayer(), false };
					Msg->QueueMessage();
				}
			}

		}
		// charge the player when below 50% health
		else if (GetHealth() < GetMaxHealth() * .50f)
		{
			MoveTowardsPlayer();
			if (currAttackStrat != VAMPIRE_TRANSFORMING && currAttackStrat != BAT_ATTACK)
			{
				// constantly attacking (spit at player)
				if (shotCooldown < 0.0f)
				{
					if (bloodRage)
						shotCooldown = .50f;
					else
						shotCooldown = 2.5f;

					CreateBulletMessage * Msg = new CreateBulletMessage{ this, RotationToPlayer(), false };
					Msg->QueueMessage();
				}
			}

			retreating = false;
		}

		// last 25% of health, +50% damage
		if (GetHealth() < GetMaxHealth() * .25f && !bloodRage && currAttackStrat != BAT_ATTACK)
		{
			bloodRage = true;
			SetDamage(int(GetDamage() * 1.5f));
			SetAugment(gameplay->RandomizeAugment());

			// flash to show 'bloodRage'
			SetFlashDuration(5);
			SetDamageFlash(true);
		}
	}
	// over 300 from player (too far away / already retreated)
	else if (distanceToPlayer > 300)
	{
		SetVelocity({ 0, 0 });

		// constantly attacking
		if (shotCooldown < 0.0f)
		{
			shotCooldown = 2.5f;
			CreateBulletMessage * Msg = new CreateBulletMessage{ this, RotationToPlayer(), false };
			Msg->QueueMessage();
		}
	}
}

void Vampire::MoveTowardsPlayer()
{
	// player to the left
	if (playerPos.x < m_ptPosition.x)
		MoveLeft();
	// player to the right
	else
		MoveRight();
}

void Vampire::BatDead(SGD::Point pos)
{
	m_ptPosition = pos;
	m_iHealth = tempHealth - GameplayState::GetInstance()->GetPlayer()->GetDamage();
	currAttackStrat = VAMPIRE_ATTACK;

	SetAugment(gameplay->RandomizeAugment());
	StartAnimation("vampiretransform");
}

/*virtual*/ void Vampire::EnterIdle()
{
	if (state == State::IDLE) return;
	Enemy::EnterIdle();

	StartAnimation("vampireidle");
}

/*virtual*/ void Vampire::EnterPatrol()
{
	if (state == State::PATROL) return;
	Enemy::EnterPatrol();

	StartAnimation("vampirewalking");
}

/*virtual*/ void Vampire::EnterCloseIn()
{
	if (state == State::CLOSEIN) return;
	Enemy::EnterCloseIn();

	StartAnimation("vampirewalking");
}

/*virtual*/ void Vampire::EnterDead()
{
	if (state == State::DEAD) return;
	Enemy::EnterDead();

	CreatePortalMessage* ptr = new CreatePortalMessage(0, GetPosition().x, GetPosition().y);
	ptr->QueueMessage();
	SetPlayerNextLevel();
	Boss::SaveHighScore();
}

/*virtual*/ void Vampire::MoveLeft(float speed)
{
	if (currAttackStrat == BAT_ATTACK)
		// moves away from the player
		Enemy::MoveLeft(-speed);
	else
		// moves towards the player
		Enemy::MoveLeft(speed);
}

/*virtual*/ void Vampire::MoveRight(float speed)
{
	if (currAttackStrat == BAT_ATTACK)
		// moves away from the player
		Enemy::MoveRight(-speed);
	else
		// moves towards the player
		Enemy::MoveRight(speed);
}

// create bats for bat mode
/*virtual*/ void Vampire::HandleEvent(const SGD::Event* pEvent) /*override*/
{
	if (pEvent->GetEventID() == "TRANSFORM_COMPLETE" && currAttackStrat == VAMPIRE_TRANSFORMING)
	{
		//Make a bat
		currAttackStrat = BAT_ATTACK;
		CreateBatMessage *msg = new CreateBatMessage(m_ptPosition.x, m_ptPosition.y - 15, this);
		msg->QueueMessage();

		for (int i = 0; i < rand() % 3 + 3; i++)
			(new CreateBatMessage(m_ptPosition.x + rand() % 120 - 60, m_ptPosition.y - rand() % 120))->QueueMessage();
	}
	else
		MovingObject::HandleEvent(pEvent);
}

// hit by a bullet in vampire mode
void Vampire::HandleCollision(GameObject* pOther)
{
	if (pOther->GetType() == OBJ_BULLET && currAttackStrat != BAT_ATTACK)
	{
		// don't shoot yourself
		if (((Projectile *)pOther)->GetOwner() == this) return;

		// call MovingObjects HandleCollision
		MovingObject::HandleCollision(pOther);

		// play hit sfx
		SGD::AudioManager::GetInstance()->PlayAudio(damageAudio);
	}

	CharacterCollision(pOther);
}

void Vampire::Retreat()
{
	playerPos.x < m_ptPosition.x ? MoveRight(150) : MoveLeft(150);
	StartAnimation("vampirewalking");
	retreating = true;
}
